package com.jichangxiu.framework.security.provider;

import com.jichangxiu.framework.security.entity.AuthToken;
import com.jichangxiu.framework.security.service.AuthUserDetailsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;

/**
 * AuthProvider:
 *
 * @author Jcx
 * @create 2023-04-04 13:35
 */
public class AuthProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {

    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

    private final AuthUserDetailsService userDetailsService;

    private final PasswordEncoder passwordEncoder;

    public AuthProvider(AuthUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Assert.isInstanceOf(AuthToken.class, authentication, () -> "不支持的登录模式");
        AuthToken authToken = (AuthToken) authentication;
        String tenantName = (String) authToken.getTenantName();
        String userInfo = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();
        UserDetails userDetails = userDetailsService.loadUserByTenantAndUserInfo(tenantName, userInfo);
        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            throw new BadCredentialsException("密码错误");
        }
        AuthToken newAuthToken = new AuthToken(tenantName, userInfo, password, userDetails.getAuthorities());
        authToken.setDetails(userDetails);
        return newAuthToken;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return AuthToken.class.isAssignableFrom(aClass);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(userDetailsService, "jcxUserDetailsService must not be null");
    }

    @Override
    public void setMessageSource(MessageSource messageSource) {
        this.messages = new MessageSourceAccessor(messageSource);
    }

}
